#pragma once 

#include <map>
#include "common.h"
#include "ResultStorage.h"

template<class TResult>
class ResultComposer
{
public:
	virtual TResult compose(int period, int tail)
	{
		return TResult();
	}
};

template<>
class ResultComposer<int>
{
public:
	virtual int compose(int period, int tail)
	{
		return period;
	}
};

struct PeriodAndTail
{
	PeriodAndTail();
	PeriodAndTail(int p, int t);
	int period;
	int tail;
	friend bool operator < (const PeriodAndTail &a, const PeriodAndTail &b);
};

template<>
class ResultComposer<PeriodAndTail>
{
public:
	PeriodAndTail compose(int period, int tail)
	{
		return PeriodAndTail(period, tail);
	}
};

template<class TGenerator, class TResult=int>
class GeneratorTester : public ResultComposer<TResult>
{
	typedef typename generator_traits<TGenerator>::State State;
	typedef typename generator_traits<TGenerator>::StateComparer StateComparer;
public:
	TResult test(TGenerator *generator, size_t maxSequenceLength) 
	{
		std::map<State, int, StateComparer> m_StateMap;
		size_t j = 0;
		for (; j < maxSequenceLength; j++)
		{
			State current_state = generator_traits<TGenerator>::next(generator);
			int index = m_StateMap[current_state];
			if(index == 0)
			{
				m_StateMap[current_state] = j + 1;
			}
			else
			{
				return compose(j - index + 1, index - 1);
			}
		}
		return TResult();
	}
};